package com.qipay.core.help;

import com.qipay.core.entity.Remark;
import com.qipay.core.entity.ValueObject;
import com.qipay.core.exception.AppException;
import com.qipay.core.exception.BaseException;
import com.qipay.core.exception.SystemException;
import com.qipay.core.utils.CommUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by admin on 2017-06-05.
 */
public class BeanHelper {
    static Log logger = LogFactory.getLog(BeanHelper.class);
    /**
     * 设置数据库实体类操作用户信息
     * modifyDate、modifyUserId 每次都设置新值
     * createDate、createUserId 只新增的才会设置
     * @param entity
     * @param <T>
     */
//    public static <T> void setUserInfo(T entity,boolean isNew) {
//        try {
//            BeanInfo beanInfo = Introspector.getBeanInfo(entity.getClass());
//            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//
//            for (PropertyDescriptor property : propertyDescriptors) {
//                String propertyName = property.getName();
//                Object value = null;
//                if (CommUtil.equalsString("createDate", propertyName)&&isNew) {
//                    value = new Date();
//                } else if (CommUtil.equalsString("createUserId", propertyName)&&isNew) {
//                    value = UserHelper.getUser().getUserId();
//                } else if (CommUtil.equalsString("modifyDate", propertyName)) {
//                    value = new Date();
//                } else if (CommUtil.equalsString("modifyUserId", propertyName)) {
//                    value = UserHelper.getUser().getUserId();
//                }
//                if (value != null) {
//                    Method setter = property.getWriteMethod();
//                    setter.invoke(entity, value);
//                }
//            }
//        } catch (Exception e) {
//            if (e instanceof BaseException) {
//                throw (BaseException) e;
//            } else {
//                throw new SystemException("设置实体Bean用户操作信息失败", e, "请联系管理员");
//            }
//        }
//    }


    /**
     * 判断Bean对应的属性是否为空
     *
     * @param bean
     * @param propertyNames
     * @return
     */
    public static void checkPropertyEmpty(Object bean, String... propertyNames) {
        checkPropertyEmpty(bean, true, propertyNames);
    }

    /**
     * 判断Bean对应的属性是否为空
     *
     * @param bean
     * @param propertyNames
     * @return
     */
    public static String checkPropertyEmpty(Object bean, boolean throwException, String... propertyNames) {

        try {
            List<String> emptyPropertyNames = new ArrayList<String>();
            String emptyProperty = "";
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            for (String propertyName : propertyNames) {
                boolean find = false;
                for (PropertyDescriptor property : propertyDescriptors) {
                    if (CommUtil.equalsString(property.getName(), propertyName)) {
                        find = true;
                        Method getter = property.getReadMethod();
                        Object propertyValue = getter.invoke(bean);
                        if (CommUtil.isEmpty(propertyValue)) {
                            Remark remark = getter.getAnnotation(Remark.class);
                            if (remark == null) {
                                remark = bean.getClass().getDeclaredField(propertyName).getAnnotation(Remark.class);
                            }
                            if (remark == null) {
                                throw new SystemException("检查对象属性异常", bean.getClass().getName() + "." + propertyName + "属性或get方法没有Remark注解不能显示属性中文名称", "请增加注解");
                            }
                            if (CommUtil.isEmpty(remark.value())) {
                                throw new SystemException("检查对象属性异常", bean.getClass().getName() + "." + propertyName + "属性或get方法没有Remark注解值不能为空,为空不能显示属性中文名称", "请增加注解值");
                            }
                            emptyPropertyNames.add(remark.value());
                            emptyProperty += remark.value() + "、";
                        }
                        break;
                    }
                }
                if (!find) {
                    throw new SystemException("检查对象属性异常", bean.getClass().getName() + "没有" + propertyName + "属性", "请联系管理员");
                }
            }
            if (CommUtil.isNotEmpty(emptyProperty)) {
                emptyProperty = emptyProperty.substring(0, emptyProperty.length() - 1);//截取最后一个顿号
                if (throwException) {
                    throw new AppException("数据完整性检查", emptyProperty + "不能为空", "请输入完整数据");
                }
            }
            return emptyProperty;
        } catch (Exception e) {
            if (e instanceof BaseException) {
                throw (BaseException) e;
            } else {
                throw new SystemException("检查对象属性异常", e, "请联系管理员");
            }
        }
    }

    /**
     * VO 转换成 Bean
     *
     * @param vo
     * @param beanClass
     * @param <T>
     * @return
     */
    public static <T> T valueObjectToBean(ValueObject vo, Class<T> beanClass) {
        try {
            T obj = beanClass.newInstance();
            BeanHelper.valueObjectToBean(vo, obj);
            return obj;
        } catch (Exception e) {
            if (e instanceof BaseException) {
                throw (BaseException) e;
            } else {
                throw new SystemException("Map转换成Bean异常", e, "请联系管理员处理");
            }
        }
    }

    /**
     * list VO 转换成 Bean
     *
     * @param
     * @param beanClass
     * @param <T>
     * @return
     */
    public static <T> List<T> valueObjectToBean(List<ValueObject> vos, Class<T> beanClass) {

        try {
            List<T> tList = new ArrayList<T>();
            for (ValueObject vo : vos) {
                try {
                    T obj = beanClass.newInstance();
                    BeanHelper.valueObjectToBean(vo, obj);
                    tList.add(obj);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            return tList;
        } catch (Exception e) {
            if (e instanceof BaseException) {
                throw (BaseException) e;
            } else {
                throw new SystemException("Map转换成Bean异常", e, "请联系管理员处理");
            }
        }
    }

    /**
     * VO 转换成 Bean
     *
     * @param vo
     * @param obj
     */
    public static void valueObjectToBean(ValueObject vo, Object obj) {
        Object value = null;
        String key = null;
        Method setter = null;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            for (PropertyDescriptor property : propertyDescriptors) {
                String propertyName = property.getName();
                key = propertyName;
                if (vo.containsKey(key)) {

                    setter = property.getWriteMethod();
                    Class[] parameterTypes = property.getWriteMethod().getParameterTypes();
                    if (CommUtil.isNotEmpty(parameterTypes)) {
                        Class parameterType = parameterTypes[0];
                        if (parameterType == Long.class) {
                            value = vo.getAsLong(key);
                        } else if (parameterType == Date.class) {
                            value = vo.getAsDateTime(key);
                        } else if (parameterType == Double.class) {
                            value = vo.getAsDouble(key);
                        } else if (parameterType == Integer.class) {
                            value = vo.getAsInteger(key);
                        } else if (parameterType == Short.class) {
                            value = vo.getAsShort(key);
                        }else if (parameterType == Byte.class) {
                            value = vo.getAsByte(key);
                        } else {
                            value = vo.get(key);
                        }
                    }
                    // 得到property对应的setter方法
                    setter.invoke(obj, value);
                }
                key = null;
                value = null;
            }
        } catch (Exception e) {
            if (e instanceof BaseException) {
                throw (BaseException) e;
            }
            if (e instanceof IllegalArgumentException && e.getMessage().startsWith("argument type mismatch")) {
                logger.error("Map转换成Bean异常", e);
                throw new SystemException("Map转换成Bean异常", setter.toString() + "要求的参数类型与" + key + ":" + value.getClass().getName() + "不一致", "请联系管理员");
            } else {
                throw new SystemException("Map转换成Bean异常", e, "请联系管理员");
            }
        }
    }

    /**
     * 原和目标属性一样的Bean属性值拷贝到目标Bean
     *
     * @param source
     * @param target
     */
    public static void copyProperties(Object source, Object target, String... ignoreProperties) {
        BeanUtils.copyProperties(source, target, ignoreProperties);
    }

    /**
     * 原和目标属性一样的Bean属性值拷贝到目标Bean
     *
     * @param source
     * @param targetClass
     * @param <T>
     * @return
     */
    public static <T> T copyProperties(Object source, Class<T> targetClass, String... ignoreProperties) {
        T target = null;
        try {
            target = targetClass.newInstance();
            copyProperties(source, target, ignoreProperties);
            return target;
        } catch (Exception e) {
            throw new SystemException("创建复制目标对象失败", e, "请联系管理员！");
        }

    }

    /**
     * 转换属性格式
     *
     * @param bean
     * @param propertyName
     * @return
     * @cn.com.pansky.entity.FormatConvert 支持的格式参加
     */
    public static String formatPropertyValue(Object bean, final String propertyName) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            Method getter = null;
            Object value = null;
            for (PropertyDescriptor property : propertyDescriptors) {
                if (CommUtil.equalsString(propertyName, property.getName())) {
                    getter = property.getReadMethod();
                    break;
                }
            }
            if (getter == null) {
                throw new SystemException("格式化属性值异常", bean.getClass().getName() + "没有" + propertyName + "属性", "请检查程序");
            }
            Class returnType = getter.getReturnType();
            value = getter.invoke(bean);
            return value != null ? value.toString() : "";
//            FormatConvert formatConvert = getter.getAnnotation(FormatConvert.class);
//            if (formatConvert == null) {
//                Field declaredField = getDeclaredField(bean.getClass(), propertyName);
//                if(declaredField!=null){
//                    formatConvert = declaredField.getAnnotation(FormatConvert.class);
//                }
//            }
//            if (CommUtil.isPrimitiveOrPrimitiveWrapper(returnType)) {
//                if (value != null) {
//                    if (formatConvert != null && (CommUtil.isNotEmpty(formatConvert.glxtDm())||CommUtil.isNotEmpty(formatConvert.glxtDictType()))) {
//                        if(CommUtil.isNotEmpty(formatConvert.dictType())&&CommUtil.isNotEmpty(formatConvert.glxtDm())
//                                &&CommUtil.isNotEmpty(formatConvert.glxtDictType())){
//                            String gldmCode = CodeHelper.getGldmCode(formatConvert.dictType(), value.toString(), formatConvert.glxtDm(), formatConvert.glxtDictType());
//                            if(CommUtil.isNotEmpty(gldmCode)){
//                                return gldmCode;
//                            }else{
//                                throw new SystemException("格式化属性值异常",bean.getClass().getName()+"."+propertyName
//                                        +"="+value+" 经过FormatConvert注解代码对照转换后的值为空"
//                                        ,"请检查对照表");
//                            }
//                        }else{
//                            throw new SystemException("格式化属性值异常",bean.getClass().getName()+"."+propertyName
//                                    +"属性的FormatConvert注解dictType、glxtDm、glxtDictType都不能为空"
//                                    ,"请检查程序");
//                        }
//                    }else  if (Number.class.isAssignableFrom(returnType)) {
//                        if (formatConvert != null && CommUtil.isNotEmpty(formatConvert.value())) {
//                            return CommUtil.number2String((Number) value, formatConvert.value());
//                        } else {
//                            return CommUtil.number2String((Number) value);
//                        }
//                    } else if (String.class.isAssignableFrom(returnType)) {
//                        if (formatConvert != null && CommUtil.isNotEmpty(formatConvert.dictType())) {
//                            return CodeHelper.getDictCnName(formatConvert.dictType(), (String) value);
//                        }else if (formatConvert != null && formatConvert.maxLength()>0) {
//                            String nValue=(String) value;
//                            return nValue.length()>formatConvert.maxLength()?nValue.substring(0,formatConvert.maxLength()):nValue;
//                        }else if (formatConvert != null) {
//                            String nValue=(String) value;
//                            return CommUtil.stringFormat(nValue,formatConvert.value());
//                        } else {
//                            return  value.toString();
//                        }
//                    } else {
//                        return value.toString();
//                    }
//                } else {
//                    return "";
//                }
//            } else if (Date.class.isAssignableFrom(returnType)) {
//                if (value != null) {
//                    if (formatConvert != null && CommUtil.isNotEmpty(formatConvert.value())) {
//                        return CommUtil.date2Str((Date) value, formatConvert.value());
//                    } else {
//                        return CommUtil.date2Str((Date) value);
//                    }
//                } else {
//                    return "";
//                }
//            } else {
//                return value!=null?value.toString():"";
//            }

        } catch (Exception e) {
            if (e instanceof BaseException) {
                throw (BaseException) e;
            } else {
                throw new SystemException("格式转换异常", e, "请联系管理员！");
            }
        }
    }

    /**
     * 递归获取父类的字段
     *
     * @param aClass
     * @param fieldName
     * @return
     */
    private static Field getDeclaredField(Class aClass, String fieldName) {
        Field[] fields = aClass.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            if (CommUtil.equalsString(fields[i].getName(), fieldName)) {
                return fields[i];
            }
        }
        if (aClass.getSuperclass() != null) {
            return getDeclaredField(aClass.getSuperclass(), fieldName);
        } else {
            return null;
        }
    }

    /**
     * 把bean转换成Map格式
     * 支持List递归转换,List转换成转换成Key:list[i].propertyName格式
     * 支持FormatConvert转换格式注解
     * 郭明粳
     *
     * @param map
     * @param bean
     * @return
     */
    public static Map<String, String> beanToMap(Map<String, String> map, Object bean) {
        Object value = null;
        String key = null;
        //判断Map和Bean是否为null
        if (map == null) {
            throw new SystemException("Bean转换成Map失败", "map不能为null", "请检查程序");
        }
        if (bean == null) {
            throw new SystemException("Bean转换成Map失败", "bean不能为null", "请检查程序");
        }
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            for (PropertyDescriptor property : propertyDescriptors) {
                String propertyName = property.getName();
                key = propertyName;
                if (key.compareToIgnoreCase("class") == 0) {
                    continue;
                }
                Method getter = property.getReadMethod();
                Class returnType = getter.getReturnType();

                if (CommUtil.isPrimitiveOrPrimitiveWrapper(returnType) || Date.class.isAssignableFrom(returnType)) {
                    map.put(key, formatPropertyValue(bean, propertyName));
                    map.put(key, formatPropertyValue(bean, propertyName));
                } else if (returnType.isAssignableFrom(List.class)) {
                    List list = (List) getter.invoke(bean);
                    if (CommUtil.isNotEmpty(list)) {
                        for (int i = 0; i < list.size(); i++) {
                            Object listValue = list.get(i);
                            if (listValue == null) {
                                map.put(key + "[" + i + "]", "");
                            } else if (listValue != null && CommUtil.isPrimitiveOrPrimitiveWrapper(listValue.getClass())) {
                                map.put(key + "[" + i + "]", listValue.toString());
                            } else if (CommUtil.equalsString(listValue.getClass().getName(), "cn.com.pansky.ach.core.base.AchFileAttached")) {
                                //如果列表中是附件对象，直接退出循环，不转换
                                break;
                            } else {
                                Map<String, String> listBeanMap = beanToMap(map.getClass().newInstance(), list.get(i));
                                Set<String> listBeanMapKeys = listBeanMap.keySet();
                                for (String listBeanMapKey : listBeanMapKeys) {
                                    Object listBeanMapValue = listBeanMap.get(listBeanMapKey);
                                    if (listBeanMapValue != null) {
                                        map.put(key + "[" + i + "]." + listBeanMapKey, listBeanMapValue.toString());
                                    } else {
                                        map.put(key + "[" + i + "]." + listBeanMapKey, "");
                                    }
                                }
                            }
                        }
                    }
                } else {
                    value = getter.invoke(bean);
                    if (value != null) {
                        Map<String, String> listBeanMap = beanToMap(map.getClass().newInstance(), value);
                        Set<String> listBeanMapKeys = listBeanMap.keySet();
                        for (String listBeanMapKey : listBeanMapKeys) {
                            Object listBeanMapValue = listBeanMap.get(listBeanMapKey);
                            if (listBeanMapValue != null) {
                                map.put(key + "." + listBeanMapKey, listBeanMapValue.toString());
                            } else {
                                map.put(key + "." + listBeanMapKey, "");
                            }
                        }
                    }

                }
            }
            return map;
        } catch (Exception e) {
            if (e instanceof BaseException) {
                throw (BaseException) e;
            } else {
                throw new SystemException("Map转换成Bean异常", e, "请联系管理员");
            }
        }
    }

    /**
     * 把bean转换成Map格式
     * 支持List递归转换,List转换成转换成Key:list[i].propertyName格式
     * 支持FormatConvert转换格式注解
     * 郭明粳
     *
     * @param map
     * @param bean
     * @return
     */
    public static Map<String, String> beanToJxlsMap(Map map, Object bean) {
        Object value = null;
        String key = null;
        //判断Map和Bean是否为null
        if (map == null) {
            throw new SystemException("Bean转换成Map失败", "map不能为null", "请检查程序");
        }
        if (bean == null) {
            throw new SystemException("Bean转换成Map失败", "bean不能为null", "请检查程序");
        }
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            for (PropertyDescriptor property : propertyDescriptors) {
                String propertyName = property.getName();
                key = propertyName;
                if (key.compareToIgnoreCase("class") == 0) {
                    continue;
                }
                Method getter = property.getReadMethod();
                Class returnType = getter.getReturnType();
                if (CommUtil.isPrimitiveOrPrimitiveWrapper(returnType) || Date.class.isAssignableFrom(returnType)) {
                    map.put(key, formatPropertyValue(bean, propertyName));
                } else if (returnType.isAssignableFrom(List.class)) {
                    List list = (List) getter.invoke(bean);
                    if (CommUtil.isNotEmpty(list)) {
                        List mapList = new ArrayList();
                        for (int i = 0; i < list.size(); i++) {
                            Object listValue = list.get(i);
                            if (listValue == null) {
                                mapList.add("");
                            } else if (listValue != null && CommUtil.isPrimitiveOrPrimitiveWrapper(listValue.getClass())) {
                                mapList.add(listValue.toString());
                            } else if (CommUtil.equalsString(listValue.getClass().getName(), "cn.com.pansky.ach.core.base.AchFileAttached")) {
                                //如果列表中是附件对象，直接退出循环，不转换
                                break;
                            } else {
                                Map<String, String> listBeanMap = beanToJxlsMap(map.getClass().newInstance(), list.get(i));
                                mapList.add(listBeanMap);
                            }
                        }
                        map.put(propertyName, mapList);
                    }
                } else {
                    throw new SystemException("Bean转换成Map失败", "不支持" + returnType.getName() + "类型", "请检查程序");
                }
            }
            return map;
        } catch (Exception e) {
            if (e instanceof BaseException) {
                throw (BaseException) e;
            } else {
                throw new SystemException("Map转换成Bean异常", e, "请联系管理员");
            }
        }
    }

    /**
     * 获取Bean属性值
     *
     * @param entity
     * @param propertyName
     * @return
     */
    public static Object getPropertyValue(Object entity, String propertyName) {
        //属性名称第一个字母转换成大写，如果属性名称长度只有1位，后面无需再截串
        propertyName = propertyName.length() > 1 ? propertyName.substring(0, 1).toUpperCase()
                + propertyName.substring(1, propertyName.length()) : propertyName.substring(0, 1).toUpperCase();
        Method getMethod = null;
        try {
            getMethod = entity.getClass().getMethod("get" + propertyName);
            return getMethod.invoke(entity);
        } catch (Exception e) {
            throw new SystemException("获取对象属性值错误", e, "请检查程序");
        }

    }
}
